# -*- coding: utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
import sys
from ctypes import *
import os
import time
import tempfile
import logging


class Benchmark:
    @staticmethod
    def getExecutePath():
        base_path = os.path.split(os.path.realpath(__file__))[0] + '/'
        if getattr(sys, 'frozen', False):
            base_path = sys._MEIPASS + '/'
        return base_path

    @staticmethod
    def cpu():
        coremark = CDLL(Benchmark.getExecutePath() + "coremark.dll")
        score = coremark.benchmarks(1, 5000)
        score = (score * 0.5 + score * 4 * 0.5) / 10
        return int(score)

    @staticmethod
    def gpu():
        class GPU_Result(Structure):
            _fields_ = [("runtime", c_int), ("score", c_int),  ("state", c_int)]

        clbenchmark = CDLL(Benchmark.getExecutePath() + "clbenchmark.dll")
        clbenchmark.benchmark.restype = GPU_Result
        res = clbenchmark.benchmark()
        if res.state != 0:
            raise Exception("call opencl error:" + str(res.state))
        return res.score

    @staticmethod
    def memory():
        memorymark = CDLL(Benchmark.getExecutePath() + "memory.dll")
        return int(memorymark.benchmark(0))

    @staticmethod
    def disk():
        report = Benchmark.iotest(1024 * 1024 * 10, 40)
        return int(1 / report * 600)

    @staticmethod
    def iotest(size=1024 * 1024 * 10, loop=1):
        file = os.path.join(tempfile.gettempdir(), 'disk_rw_test.bin')
        if os.path.exists(file):
            os.remove(file)
        buffer = bytearray(size)
        start = time.time()
        for i in range(loop):
            f = open(file, 'wb+', buffering=0)
            f.write(buffer)
            f.close()
            f = open(file, 'wb+', buffering=0)
            f.read(size)
            f.close()
        end = time.time()
        os.remove(file)
        used_time = end - start
        if used_time == 0:
            used_time = 0.00001
        return used_time

    @staticmethod
    def all():
        call_names = [
            'cpu',
            'gpu',
            'disk',
            'memory'
        ]
        results = {
            'score': 0,
            'cpu': {'star': 0, 'score': 0},
            'gpu': {'star': 0, 'score': 0},
            'disk': {'star': 0, 'score': 0},
            'memory': {'star': 0, 'score': 0},
            'has_error': False
        }

        def call(name):
            try:
                score = Benchmark.__dict__[name].__func__()
                results['score'] = results['score'] + score
                results[name] = {'star': 0, 'score': score}
            except Exception as e:
                results[name] = {'star': 0, 'score': 0}
                results[name + '_error'] = str(e)
                results['has_error'] = True
                logging.error(e)
        try:
            executor = ThreadPoolExecutor(max_workers=len(call_names))
            for result in executor.map(call, call_names, timeout=5):
                result
        except Exception as e:
            logging.error("benchmark timeout error", e)
        return results


if __name__ == "__main__":
    print(Benchmark.all())
